package com.katze.boot.common.domain;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Function;


public class DataObject implements Serializable {

    @Serial
    private static final long serialVersionUID = 5020448888891733732L;

    private static final Logger log = LoggerFactory.getLogger(DataObject.class);

    private byte[] data;

    public DataObject(byte[] data){
        this.data = data;
    }

    public String asString(){
        return read((i) -> new String(getData()));
    }

    public InputStream asInputStream(){
        return new ByteArrayInputStream(this.getData());
    }

    public Properties asProperties(){
        return read((i) ->{
            Properties properties = new Properties();
            try (InputStreamReader reader= new InputStreamReader(new ByteArrayInputStream(this.getData()), StandardCharsets.UTF_8)){
                properties.load(reader);
            }catch (Exception e){
                log.error("转换异常：{}", e.getMessage(), e);
            }
            return properties;
        });
    }

    public <T>T asYaml(Class<T> clazz){
        return read((i) -> new Yaml().loadAs(new ByteArrayInputStream(this.getData()), clazz));
    }

    public <T>T asBean(Class<T> clazz){
        return read((i) ->{
            try {
                return getObjectMapper().readValue(this.getData(), clazz);
            } catch (IOException e) {
                log.error("to bean fail", e);
            }
            return null;
        });
    }

    public <T>T asBean(TypeReference<T> typeReference){
        if(Optional.ofNullable(this.getData()).isPresent()){
            try {
                return getObjectMapper().readValue(this.getData(), typeReference);
            } catch (IOException e) {
                log.error("to bean fail", e);
            }
        }
        return null;
    }

    public <T>List<T> asList(Class<T> clazz){
        if(Optional.ofNullable(this.getData()).isPresent()){
            try {
                ObjectMapper mapper = getObjectMapper();
                JavaType javaType = mapper.getTypeFactory().constructCollectionType(List.class, clazz);
                return mapper.readValue(this.getData(), javaType);
            } catch (IOException e) {
                log.error("to list fail", e);
            }
        }
        return null;
    }

    public JsonNode asTree() {
        try {
            return getObjectMapper().readTree(this.getData());
        } catch (IOException e) {
            log.error("to tree fail", e);
        }
        return null;
    }

    private <T>T read(Function<byte[], T> fun){
        return this.getData().length > 0? fun.apply(this.getData()):null;
    }

    protected byte[] getData() {
        return data == null? new byte[]{}:data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    protected ObjectMapper getObjectMapper(){
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); // 控制字段顺序，同时保证list集合中的元素顺序
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }
}
